<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .red {
            color: red;
        }
        .green {
            color: green;
        }
    </style>
</head>
<body>
    <div id="app"></div>
</body>
<script>
    function shouldSetAsProps(key, el) {
        if (key === 'form' && el.tagName === 'INPUT') return false
        return key in el
    }
    function createRenderer (options) {
        const { createElement, setElementText, insert, patchProps } = options
        function render(vnode, container) {
            if (vnode) {
                patch(container._vnode, vnode, container)
            } else {
                if (container._vnode) {
                    container.innerHTML = ''
                }
            }
            container._vnode = vnode
        }
        function patch(n1, n2, container) {
            // 没有旧vnode
            if (!n1) {
                // 直接挂载
                mountElement(n2, container)
            } else {
                // n1存在 打补丁
            }
        }
        // 挂载 
        function mountElement(vnode, container) {
            const el = createElement(vnode.type)
            if (vnode.props) {
                for(key in vnode.props) {
                    patchProps(key, el, null, vnode.props[key])
                }
            }
            if (typeof vnode.children === 'string') {
                setElementText(el, vnode.children)
            } else if (Array.isArray(vnode.children)) {
                vnode.children.forEach(n => {
                    patch(null, n, el)
                });
            }
            insert(el, container)
        } 

        return {
            render,
        }
    }

    const renderer = createRenderer({
        createElement(tag) {
            return document.createElement(tag);
        },
        setElementText(el, text) {
            el.textContent = text;
        },
        insert(el, parent, anchor = null) {
            parent.insertBefore(el, anchor);
        },
        patchProps(key, el, preValue, nextValue) {
            // 如果要设置的属性key 存在对应的DOM properties属性
            if (shouldSetAsProps(key, el)) {
                // 获取对应DOM properties属性的类型
                const type = typeof el[key]
                // console.log('走DOM Properties设置属性=', key, type)
                if (type === 'boolean' && nextValue === '') {
                    el[key] = true
                } else {
                    el[key] = nextValue
                }
            } else {
                // 如果要设置的属性key没有对应的DOM properties属性，那就通过setAttribute设置
                // console.log('走setAttribute设置属性=', key)
                el.setAttribute(key, nextValue)
            }
        }
    })
    const vnode = {
        type: 'div',
        props: {
            id: 'div1',
            class: 'container_class'
        },
        children: [
            {
                type: 'h1',
                props: {
                    class: 'red'
                },
                children: 'hello'
            },
            {
                type: 'h2',
                props: {
                    class: 'green'
                },
                children: 'hello2'
            },
            {
                type: 'form',
                props: {
                    id: 'formId'
                },
                children: [
                    {
                        type: 'input',
                        props: {
                            form: 'https://baidu.com',
                            disabled: '',
                            value: '123'
                        }
                    }
                ]
            }
        ]
    }
    renderer.render(vnode, document.getElementById('app'))

    // 总结
    // 1. 设置正确的元素属性的关键是先设置DOM properties再设置setAttributes，其中包括DOM properties布尔值的处理、input中form属性只能用setAttributes设置等还有一些特殊操作需要注意。
    // 2. 把属性相关的渲染逻辑从渲染器中抽离出来
</script>
</html>